﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xplang.abstractions;
using xplang.run;

namespace xplang.rtl.native
{
  public class IntClass : NativeClass
  {

    internal IntClass()
      : base(RTL.rtl, "Integer")
    {
      genericParams = new GenericParamDecl[] { };
      ClassRef _this = getRef(null);
      inheritance = new ClassRef[]{
        xplang.rtl.RTL.equatableClass.getRef(new ClassRef[]{_this}),
        xplang.rtl.RTL.comparableClass.getRef(new ClassRef[]{_this}),
        xplang.rtl.RTL.addableClass.getRef(new ClassRef[]{_this}),
        xplang.rtl.RTL.incrementableClass.getRef(null),
        xplang.rtl.RTL.decrementableClass.getRef(null)
      };
    }

    public override void registerMembers()
    {
      xplang.rtl.RTL.comparableClass.mGE.registerImplementation(this, execGE);
      xplang.rtl.RTL.comparableClass.mGT.registerImplementation(this, execGT);
      xplang.rtl.RTL.comparableClass.mLE.registerImplementation(this, execLE);
      xplang.rtl.RTL.comparableClass.mLT.registerImplementation(this, execLT);

      xplang.rtl.RTL.addableClass.mAdd.registerImplementation(this, execAdd);
      xplang.rtl.RTL.incrementableClass.mInc.registerImplementation(this, execInc);
      xplang.rtl.RTL.decrementableClass.mDec.registerImplementation(this, execDec);
    }

    public Value execGE(Value[] heap, ref FlowState state)
    {
      Int64 l = (Int64)heap[0].pointer;
      Int64 r = (Int64)heap[1].pointer;
      return new Value(xplang.rtl.RTL.booleanClass.getRef(null), l >= r);
    }

    public Value execGT(Value[] heap, ref FlowState state)
    {
      Int64 l = (Int64)heap[0].pointer;
      Int64 r = (Int64)heap[1].pointer;
      return new Value(xplang.rtl.RTL.booleanClass.getRef(null), l > r);
    }

    public Value execLE(Value[] heap, ref FlowState state)
    {
      Int64 l = (Int64)heap[0].pointer;
      Int64 r = (Int64)heap[1].pointer;
      return new Value(xplang.rtl.RTL.booleanClass.getRef(null), l <= r);
    }

    public Value execLT(Value[] heap, ref FlowState state)
    {
      Int64 l = (Int64)heap[0].pointer;
      Int64 r = (Int64)heap[1].pointer;
      return new Value(xplang.rtl.RTL.booleanClass.getRef(null), l < r);
    }

    public Value execAdd(Value[] heap, ref FlowState state)
    {
      Int64 l = (Int64)heap[0].pointer;
      Int64 r = (Int64)heap[1].pointer;
      return new Value(xplang.rtl.RTL.intClass.getRef(null), l + r);
    }

    public Value execInc(Value[] heap, ref FlowState state)
    {
      return new Value(xplang.rtl.RTL.intClass.getRef(null), ((Int64)heap[0].pointer) + 1);
    }

    public Value execDec(Value[] heap, ref FlowState state)
    {
      return new Value(xplang.rtl.RTL.intClass.getRef(null), ((Int64)heap[0].pointer) - 1);
    }

    //public override bool canIncrement()
    //{
    //  return true;
    //}

    //public override bool canDecrement()
    //{
    //  return true;
    //}

    //public override void executeIncrement(Value value)
    //{
    //  value.objRef = (Int64)(value.objRef) + 1;
    //}

    //public override void executeDecrement(Value value)
    //{
    //  value.objRef = (Int64)(value.objRef) - 1;
    //}

    //public override bool canCompare(ClassDecl rightType)
    //{
    //  return rightType.extends(xplang.rtl.RTL.intClass)
    //    || rightType.extends(xplang.rtl.RTL.doubleClass);
    //}

    //public override int executeCompare(ClassDecl rightType, Value lValue, Value rValue)
    //{
    //  Int64 l = (Int64)(lValue.objRef);
    //  Int64 r = (Int64)(rValue.objRef);
    //  if (l == r)
    //    return 0;
    //  if (l > r)
    //    return 1;
    //  return -1;
    //}

    //public override bool canAdd(ClassDecl rightType)
    //{
    //  return rightType.extends(xplang.rtl.RTL.intClass);
    //}

    //public override Object execAdd(ClassDecl rightType, Value left, Value right)
    //{
    //  Int64 l = (Int64)(left.objRef);
    //  Int64 r = (Int64)(right.objRef);
    //  return l + r;
    //}

    public override object newInstance()
    {
      return new Int64();
    }

    public override Value getAttributeValue(Value _this, Variable variable)
    {
      throw new NotImplementedException();
    }

    public override void setAttributeValue(Value _this, Variable variable, Value obj)
    {
      throw new NotImplementedException();
    }
  }
}
